/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Trab2;

import java.util.ArrayList;

/**
 *
 * @author Marcela.Farias
 */
public class PasswordChecker02 implements PasswordChecker{

       
     public ArrayList<String> checkPassword(String pwd) {
         
        String res = "";
        ArrayList<String> result = new ArrayList<>();
        Integer score = new Integer(getScore(pwd));
        result.add(score.toString());
        
        if (score >= 0 && score < 20) { 
             res = "Very Weak"; 
        }
	else if (score >= 20 && score < 40) { 
             res = "Weak"; 
        }
	else if (score >= 40 && score < 60) { 
             res = "Medium"; 
        }
	else if (score >= 60 && score < 80) { 
             res  = "Strong"; 
        }
        else if (score >= 80 && score <= 100) { 
            res = "Very Strong"; 
       }
        result.add(res);
        
        return result;
        
    }
     
    private char[] pwdToArray(String pwd)
    {
        char[] pwd2 = pwd.replaceAll("\\s+", "").toCharArray();
        return pwd2;
    }
    
    // Verificações
    
    @Override
    public int CheckLenght(String pwd) {
        return pwd.length();
    }
    
    @Override
    public int CheckUpperCase(String pwd)
    {
        char[] passwd = pwdToArray(pwd);
        int nUC = 0;
        for (char a: passwd){
            if (Character.isLetter(a) && Character.isUpperCase(a)) {
               nUC++;
            }
        }
        return nUC;
    }
    
    @Override
    public int CheckLowerCase(String pwd)
    {
        char[] passwd;
        passwd = pwdToArray(pwd);
        int nLC = 0;
        for (char a: passwd){
            if (Character.isLetter(a) && Character.isLowerCase(a)) {
               nLC++;
            }
        }
        return nLC;
    }
    
    @Override
    public int CheckDigits(String pwd)
    {
        char[] passwd = pwdToArray(pwd);
        int nNumber = 0;
        for (char a: passwd){
            if (Character.isDigit(a)) {
               nNumber++;
            }
        }
        return nNumber;
    }

    @Override
    public int CheckSimbs(String pwd)
    {
        char[] passwd = pwdToArray(pwd);
        int nSymbol = 0;
        for (char a: passwd){
            if ((!Character.isDigit(a) && !Character.isLetter(a))) {
               nSymbol++;
            }
        }
        return nSymbol;
    }
    
    private int checkMidChar(String pwd){
        char[] passwd = pwdToArray(pwd);
        int nMidChar = 0;
        int pLenght = passwd.length;
        for (int i = 0; i < pLenght ; i++){
            if (Character.isDigit(passwd[i])) { // OK
                 if (i > 0 && i < (pLenght - 1)) { 
                     nMidChar++;
                 }
            }
            else if (!Character.isDigit(passwd[i]) && !Character.isLetter(passwd[i])) {
                 if (i > 0 && i < (pLenght - 1)) { 
                     nMidChar++; 
                 }
            }
        }
        return nMidChar;
    }
 
    private int CheckConsecAlphaLC(char[] passwd)
    {
        int nTmpAlphaLC = 0, nConsecAlphaLC = 0;     
        for (int i = 0; i < passwd.length ; i++){
            if (Character.isLetter(passwd[i]) && Character.isLowerCase(passwd[i])) {
                if ((nTmpAlphaLC != -1) && ((nTmpAlphaLC + 1) == i)) { 
                        nConsecAlphaLC++;
                    } 
                }
            nTmpAlphaLC = i;
            }  
        return nConsecAlphaLC;
    }
    
    private int CheckConsecAlphaUC(char[] passwd)
    {
        int nTmpAlphaUC = 0, nConsecAlphaUC = 0;     
        for (int i = 0; i < passwd.length ; i++){
            if (Character.isLetter(passwd[i]) && Character.isUpperCase(passwd[i])) {
                if ((nTmpAlphaUC != -1) && ((nTmpAlphaUC + 1) == i)) { 
                        nConsecAlphaUC++;
                    } 
                }
            nTmpAlphaUC = i;
            }  
        return nConsecAlphaUC;
    }

    private int CheckConsecDigit(char[] passwd)
    {
        int nTmpNumber = 0, nConsecNumber = 0;     
        for (int i = 0; i < passwd.length ; i++){
            if (Character.isDigit(passwd[i])) {
                if ((nTmpNumber != -1) && ((nTmpNumber + 1) == i)) { 
                        nConsecNumber++;
                    } 
                }
            nTmpNumber = i;
            }  
        return nConsecNumber;
    }
    

    private int CheckConsecSymbols(char[] passwd)
    {
        int nTmpSymbol = 0, nConsecSymbol = 0;     
        for (int i = 0; i < passwd.length ; i++){
            if ((!Character.isDigit(passwd[i]) && !Character.isLetter(passwd[i]))) {
                if ((nTmpSymbol != -1) && ((nTmpSymbol + 1) == i)) { 
                        nConsecSymbol++;
                    } 
                }
            nTmpSymbol = i;
            }  
        return nConsecSymbol;
    }
    
    private int checkRepeatCharacters(String pwd){
        char[] passwd = pwdToArray(pwd);
	boolean bCharExists = false;
        int nRepInc = 0, nRepChar = 0, nUnqChar = 0;
        for (int i=0; i < passwd.length; i++) {
            for (int b=0; b < passwd.length; b++) {
                if (passwd[i] == passwd[b] && i != b) {
                    bCharExists = true;
                    nRepInc += Math.abs((double)passwd.length/(b-i));
                }
            }
        
            if (bCharExists) {
                nRepChar++;
                nUnqChar = passwd.length-nRepChar;
                nRepInc = (nUnqChar != 0) ? (int)Math.ceil(nRepInc/nUnqChar) : (int)Math.ceil(nRepInc);
            } 
        }
        return nRepInc;
    }
    
   private int checkAlphaPatterns(String pwd){
       String sAlphas = "abcdefghijlmnopqrstuvwxyz";
       int nSeqAlpha = 0;
       for (int s=0; s < sAlphas.length(); s++) {
            String sFwd = sAlphas.substring(s,s+3);
            String sRev = new StringBuffer(sFwd).reverse().toString();
		if (pwd.toLowerCase().indexOf(sFwd) != -1 || pwd.toLowerCase().indexOf(sRev) != -1) { 
                    nSeqAlpha++; 
                }
        }
       return nSeqAlpha;
   }
   
   private int checkNumericPatterns(String pwd){
       String sNumerics = "01234567890";
       int nSeqNumber = 0;
       for (int s=0; s < sNumerics.length(); s++) {
            String sFwd = sNumerics.substring(s,s+3);
            String sRev = new StringBuffer(sFwd).reverse().toString();
		if (pwd.toLowerCase().indexOf(sFwd) != -1 || pwd.toLowerCase().indexOf(sRev) != -1) { 
                    nSeqNumber++;
                }
       }
       return nSeqNumber;
   }
   
   private int checkSymbolsPatterns(String pwd){
       int nSeqSymbol = 0;
       for (int s=0; s < Simbolos.size(); s++) {
            String sFwd = (Simbolos.subList(s, s+3)).toString();
	    String sRev = new StringBuffer(sFwd).reverse().toString();
		if (pwd.toLowerCase().indexOf(sFwd) != -1 || pwd.toLowerCase().indexOf(sRev) != -1) { 
                    nSeqSymbol++;
                }
	}
       return nSeqSymbol;
   }
   
   // Cálculos de pontuação
   
   private int getLenghtBonus(String pwd){
       int nMultLength =4, nScoreLenght = 0;
       nScoreLenght = CheckLenght(pwd) * nMultLength;
       
       return nScoreLenght;
   }
   
   private int getAlphaUCBonus(String pwd){
       int nAlphaUC = CheckUpperCase(pwd);
       int nScoreAlphaUC = 0;
       if (nAlphaUC > 0 && nAlphaUC < CheckLenght(pwd)) {
            nScoreAlphaUC = (CheckLenght(pwd) - nAlphaUC) * 2;
       }
       return nScoreAlphaUC;
   }
   
   private int getAlphaLCBonus(String pwd){
       int nAlphaLC = CheckLowerCase(pwd);
       int nScoreAlphaLC = 0;
       if (nAlphaLC > 0 && nAlphaLC < CheckLenght(pwd)) {
            nScoreAlphaLC = (CheckLenght(pwd) - nAlphaLC) * 2;
       }
       return nScoreAlphaLC;
   }
   
   private int getNumberBonus(String pwd){
       int nNumber = CheckDigits(pwd);
       int nScoreNumber = 0, nMultNumber = 4;
       if (nNumber > 0 && nNumber < CheckLenght(pwd)) {
            nScoreNumber = nNumber * nMultNumber;
       }
       return nScoreNumber;
   }
   
   private int getSymbolBonus(String pwd){
       int nSymbol = CheckSimbs(pwd);
       int nScoreSymbol = 0, nMultSymbol = 6;
       if (nSymbol > 0) {
            nScoreSymbol = nSymbol * nMultSymbol;
       }
       return nScoreSymbol; 
   }
   
   private int getMidCharBonus(String pwd){
       int nMidChar = checkMidChar(pwd);
       int nScoreMidChar = 0, nMultMidChar=2;
       if (nMidChar > 0) {
            nScoreMidChar = nMidChar * nMultMidChar;
       }
       return nScoreMidChar; 
   }
   
   private int getAlphasOnlyBonus(String pwd){
       int nAlphaLC = 0, nAlphaUC = 0, nNumber = 0, nSymbol = 0, nScore = 0, nLength = 0, nAlphasOnly = 0;
       nAlphaLC = CheckLowerCase(pwd);
       nAlphaUC = CheckUpperCase(pwd);
       nNumber = CheckDigits(pwd);
       nSymbol = CheckSimbs(pwd);
       nLength= CheckLenght(pwd);
       
       if ((nAlphaLC > 0 || nAlphaUC > 0) && nSymbol == 0 && nNumber == 0) {
			nScore = nScore - nLength;
			nAlphasOnly = nLength;
       }
       return nScore;
   }
   
   private int getNumbersOnlyBonus(String pwd){
       int nAlphaLC = 0, nAlphaUC = 0, nNumber = 0, nSymbol = 0, nScore = 0, nLength = 0, nNumbersOnly = 0;
       nAlphaLC = CheckLowerCase(pwd);
       nAlphaUC = CheckUpperCase(pwd);
       nNumber = CheckDigits(pwd);
       nSymbol = CheckSimbs(pwd);
       nLength= CheckLenght(pwd);
       
       if (nAlphaLC == 0 && nAlphaUC == 0 && nSymbol == 0 && nNumber > 0) {
			nScore = nScore - nLength;
			nNumbersOnly = nLength;
       }
       return nScore;
   }
   
   private int getRepCharBonus(String pwd){
       int nRepInc = 0, nScore = 0;
       nRepInc = checkRepeatCharacters(pwd);       
       if (nRepInc > 0) {
	   nScore = -nRepInc;
       }
       return nScore;
   } 
   
   private int getConsecAlphaUCBonus(String pwd){
       int nConsecAlphaUC = 0, nScore = 0, nMultConsecAlphaUC = 2;
       nConsecAlphaUC = CheckConsecAlphaUC(pwd.toCharArray());
       if (nConsecAlphaUC > 0) {
            nScore = - nConsecAlphaUC * nMultConsecAlphaUC;
       }
       return nScore;       
   }
   
   private int getConsecAlphaLCBonus(String pwd){
       int nConsecAlphaLC = 0, nScore = 0, nMultConsecAlphaLC = 2;
       nConsecAlphaLC = CheckConsecAlphaLC(pwd.toCharArray());
       if (nConsecAlphaLC > 0) {
            nScore = - nConsecAlphaLC * nMultConsecAlphaLC;
       }
       return nScore;    
   }
   
   private int getConsecNumberBonus(String pwd){
       int nConsecNumbers = 0, nScore = 0, nMultCosecNumbers = 2;
       nConsecNumbers = CheckConsecDigit(pwd.toCharArray());
       if (nConsecNumbers > 0) {
            nScore = - nConsecNumbers * nMultCosecNumbers;
       }
       return nScore;    
   }   
   
   private int getSeqAlphaBonus(String pwd){
       int nSeqAlpha = 0, nScore = 0, nMultSeqAlpha = 3;
       nSeqAlpha = checkAlphaPatterns(pwd);
       if (nSeqAlpha > 0) {
            nScore = - nSeqAlpha * nMultSeqAlpha;
       }
       return nScore;    
   }
   
   private int getSeqNumberBonus(String pwd){
       int nSeqNumber = 0, nScore = 0, nMultSeqNumber = 3;
       nSeqNumber = checkNumericPatterns(pwd);
       if (nSeqNumber > 0) {
            nScore = - nSeqNumber * nMultSeqNumber;
       }
       return nScore;    
   }
   
  private int getSeqSymbolBonus(String pwd){
       int nSeqSymbol = 0, nScore = 0, nMultSeqSymbol = 3;
       nSeqSymbol = checkSymbolsPatterns(pwd);
       if (nSeqSymbol > 0) {
            nScore = - nSeqSymbol * nMultSeqSymbol;
       }
       return nScore;    
   }
  
  private int getRequirements(String pwd){
      int nMinPwdLen = 8, nReqChar = 0, nRequirements = 0, nScore = 0;
      int nLength = CheckLenght(pwd),
          nAlphaUC = CheckUpperCase(pwd),
          nAlphaLC = CheckLowerCase(pwd),
          nNumber = CheckDigits(pwd),
          nSymbol = CheckSimbs(pwd);
      
      int[] arrChars = { nLength, nAlphaUC, nAlphaLC, nNumber, nSymbol };
      int arrCharsLen = arrChars.length;
      int minVal;
            for (int c=0; c < arrCharsLen; c++) {
                 if (c==0) { 
                     minVal = nMinPwdLen - 1; 
                 } 
                 else { 
                     minVal = 0; 
                 }
		 if (arrChars[c] == (minVal + 1)) { 
                     nReqChar++; 
                 }
		 else if (arrChars[c] > (minVal + 1)) { 
                     nReqChar++; 
                 }
            }

		nRequirements = nReqChar;
                int nMinReqChars;
		if (CheckLenght(pwd) >= nMinPwdLen) { 
                    nMinReqChars = 3; 
                } 
                else { 
                    nMinReqChars = 4; 
                }
		if (nRequirements > nMinReqChars) {
			nScore = nRequirements * 2;
		}
      
      return nScore;
  }
   
   
   private int getScore(String pwd){
       int nScore = 0;
       if (pwd != null && !pwd.equals("")) {
           nScore += getAlphaLCBonus(pwd);
           nScore += getAlphaUCBonus(pwd);
           nScore += getAlphasOnlyBonus(pwd);
           nScore += getConsecAlphaLCBonus(pwd);
           nScore += getConsecAlphaUCBonus(pwd);
           nScore += getConsecNumberBonus(pwd);
           nScore += getLenghtBonus(pwd);
           nScore += getMidCharBonus(pwd);
           nScore += getNumberBonus(pwd);
           nScore += getNumbersOnlyBonus(pwd);
           nScore += getRepCharBonus(pwd);
           nScore += getRequirements(pwd);
           nScore += getSeqAlphaBonus(pwd);
           nScore += getSeqNumberBonus(pwd);
           nScore += getSeqSymbolBonus(pwd);
           nScore += getSymbolBonus(pwd);

           if (nScore > 100) { 
               nScore = 100; 
           } 
           else if (nScore < 0) { 
               nScore = 0;
           } 

           return nScore;
        }
        else
           return nScore;
   }
   
}

